﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects.DataClasses;
using System.Data.Objects;
using System.Data;
using CoolERP_Entities;
using System.Collections;

namespace CoolERP_DAL
{
    public interface IDAL<T>
    {
        bool Insert(T entity);
        bool Inserts(IList<T> items);

        bool Delete(T entity);
        bool Deletes(string key, string ids);
        bool Deletes(IList<T> items);

        bool Update(T entity);
        bool Updates(IList<T> items);
        bool Update<TEntity>(T entity, IList<TEntity> delMXB);

        bool IsExist(Func<T, bool> exp);
        int SaveEntity(T entity, Func<T, bool> exp);

        T GetEntity(Func<T, bool> exp);
        T GetModel(Func<T, bool> exp);

        IList<T> GetList(Func<T, bool> exp);
        IList<T> GetList(Func<T, bool> exp, string orderExpr, int takeCount);
        IList<T> GetPagerList(Func<T, bool> exp, string orderExpr, int? pageIndex, int pageSize, out int totalCount);
        IList<T> GetAll();
        bool Save();
    }

    public abstract class BaseDAL<T> : IDAL<T> where T : EntityObject
    {
        protected ErpEntities dataContext;
        public BaseDAL(IUnitOfWork context)
        {
            if (context == null) throw new ArgumentException("context");
            this.dataContext = context as ErpEntities;
            //启用自跟踪实体时此属性无效，此时不加载关联对象
            this.dataContext.ContextOptions.LazyLoadingEnabled = false;//延迟加载，是否加载外键关联表（默认是true->加载，false->不加载）
        }

        #region IDAL<T> 成员
        public virtual bool Insert(T entity)
        {
            dataContext.CreateObjectSet<T>().AddObject(entity);
            return Save();
        }

        public virtual bool Inserts(IList<T> items)
        {
            bool result = true;
            dataContext.Connection.Open();
            using (var bs = dataContext.Connection.BeginTransaction())
            {
                try
                {
                    foreach (var item in items)
                        dataContext.CreateObjectSet<T>().AddObject(item);
                    if (Save())
                        bs.Commit();
                }
                catch
                {
                    bs.Rollback();
                    return false;
                }
                finally
                {
                    dataContext.Connection.Close();
                }
            }
            return result;
        }

        public virtual bool Delete(T entity)
        {
            dataContext.DeleteObject(entity);
            return Save();
        }

        public virtual bool Deletes(string key, string ids)
        {
            bool result = true;
            dataContext.Connection.Open();
            using (var bs = dataContext.Connection.BeginTransaction())
            {
                try
                {
                    if (!string.IsNullOrEmpty(ids))
                    {
                        #region====主键ID非INT型加单引号====
                        int isNan;
                        string[] idsList = ids.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                        if (!int.TryParse(idsList[0], out isNan))
                        {
                            ids = string.Empty;
                            for (int i = 0; i < idsList.Length; i++)
                                ids += string.Format(",'{0}'", idsList[i]);
                            ids = ids.Trim(',');
                        }
                        #endregion
                        string sql = string.Format("Delete {0} Where {1} in({2})", typeof(T).Name, key, ids);
                        int count = dataContext.ExecuteStoreCommand(sql);//返回受影响的行数
                        if (count > 0)
                            bs.Commit();
                    }
                }
                catch
                {
                    bs.Rollback();
                    return false;
                }
                finally
                {
                    dataContext.Connection.Close();
                }
            }
            return result;
        }

        public virtual bool Deletes(IList<T> items)
        {
            bool result = false;
            dataContext.Connection.Open();
            using (var bs = dataContext.Connection.BeginTransaction())
            {
                try
                {
                    foreach (var item in items)
                        dataContext.DeleteObject(item);
                    if (Save())
                    {
                        bs.Commit();
                        result = true;
                    }
                }
                catch
                {
                    bs.Rollback();
                    return false;
                }
                finally
                {
                    dataContext.Connection.Close();
                }
            }
            return result;
        }

        public virtual bool Update(T entity)
        {
            if (!dataContext.IsAttached(entity))
                dataContext.Attach(entity);
            dataContext.SetAllModified(entity);
            return Save();
        }

        public virtual bool Updates(IList<T> items)
        {
            bool result = false;
            dataContext.Connection.Open();
            using (var bs = dataContext.Connection.BeginTransaction())
            {
                try
                {
                    foreach (var item in items)
                    {
                        if (!dataContext.IsAttached(item))
                            dataContext.Attach(item);
                        dataContext.SetAllModified(item);
                    }
                    if (Save())
                    {
                        bs.Commit();
                        result = true;
                    }
                }
                catch
                {
                    bs.Rollback();
                    return false;
                }
                finally
                {
                    dataContext.Connection.Close();
                }
            }
            return result;
        }

        /// <summary>
        /// 更新实体时，同时删除旧的外键明细
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entity"></param>
        /// <param name="delMXB"></param>
        /// <returns></returns>
        public virtual bool Update<TEntity>(T entity, IList<TEntity> delMXB)
        {
            bool result = false;
            dataContext.Connection.Open();
            using (var bs = dataContext.Connection.BeginTransaction())
            {
                try
                {
                    foreach (var item in delMXB)
                        dataContext.DeleteObject(item);
                    if (!dataContext.IsAttached(entity))
                        dataContext.Attach(entity);
                    dataContext.SetAllModified(entity);
                    if (Save())
                    {
                        bs.Commit();
                        result = true;
                    }
                }
                catch (Exception err)
                {
                    bs.Rollback();
                    return false;
                }
                finally
                {
                    dataContext.Connection.Close();
                }
            }
            return result;
        }

        public virtual bool IsExist(Func<T, bool> exp)
        {
            return dataContext.CreateObjectSet<T>().Where(exp).Count() > 0;
        }

        public virtual int SaveEntity(T entity, Func<T, bool> exp)
        {
            int result = 0;
            try
            {
                if (exp != null && IsExist(exp))
                    result = -1;
                else
                {
                    if (entity.EntityState == EntityState.Modified)
                        result = Update(entity) ? 1 : 0;
                    else
                        result = Insert(entity) ? 1 : 0;
                }
            }
            catch (Exception err)
            { }
            return result;
        }

        public virtual T GetEntity(Func<T, bool> exp)
        {
            var entity = dataContext.CreateObjectSet<T>().FirstOrDefault(exp);
            //if (entity != null)
            //    dataContext.Detach(entity);
            return entity;
        }

        public virtual T GetModel(Func<T, bool> exp)
        {
            this.dataContext.ContextOptions.LazyLoadingEnabled = true;
            var entity = dataContext.CreateObjectSet<T>().FirstOrDefault(exp);
            return entity;
        }

        public virtual IList<T> GetList(Func<T, bool> exp)
        {
            return dataContext.CreateObjectSet<T>().Where(exp).ToList();
        }

        public virtual IList<T> GetList(Func<T, bool> exp, string orderExpr, int takeCount)
        {
            IQueryable<T> result = dataContext.CreateObjectSet<T>();
            if (exp != null)
                result = result.Where(exp).AsQueryable();
            if (!string.IsNullOrEmpty(orderExpr))
                result = SortingExtensions.OrderUsingSortExpression(result, orderExpr);
            if (takeCount > 0)
                return result.Take(takeCount).ToList();
            else
                return result.ToList();
        }

        /// <summary>
        /// 分页
        /// </summary>
        public virtual IList<T> GetPagerList(Func<T, bool> exp, string orderExpr, int? pageIndex, int pageSize, out int totalCount)
        {
            IQueryable<T> result = dataContext.CreateObjectSet<T>();
            if (exp != null)
                result = result.Where(exp).AsQueryable();
            totalCount = result.Count();
            if (!string.IsNullOrEmpty(orderExpr))
                result = SortingExtensions.OrderUsingSortExpression(result, orderExpr);
            if (pageIndex == null)
                return result.ToList();
            else
                return result.Skip(Convert.ToInt32(--pageIndex) * pageSize).Take(pageSize).ToList();
        }

        public virtual IList<T> GetAll()
        {
            return dataContext.CreateObjectSet<T>().ToList();
        }

        public bool Save()
        {
            return dataContext.Commit() > 0;
        }
        #endregion
    }

    #region   linq to entity 扩展
    public class RuleViolation
    {
        public string ErrorMessage { get; private set; }
        public string PropertyName { get; private set; }

        public RuleViolation(string errorMessage)
        {
            ErrorMessage = errorMessage;
        }

        public RuleViolation(string errorMessage, string propertyName)
        {
            ErrorMessage = errorMessage;
            PropertyName = propertyName;
        }
    }

    public static class ObjectContextExtension
    {
        public static bool IsAttached(this ObjectContext context, object entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            ObjectStateEntry entry;
            try
            {
                entry = context.ObjectStateManager.GetObjectStateEntry(entity);
                return (entry.State != EntityState.Detached);
            }
            catch (Exception ex)
            {
            }
            return false;
        }

        public static void SetAllModified(this ObjectContext objectContext, IEntityWithKey item)
        {
            ObjectStateEntry stateEntry = objectContext.ObjectStateManager.GetObjectStateEntry(item) as ObjectStateEntry;
            IEnumerable propertyNameList = stateEntry.CurrentValues.DataRecordInfo.FieldMetadata.Select(pn => pn.FieldType.Name);
            foreach (string propName in propertyNameList)
            {
                stateEntry.SetModifiedProperty(propName);
            }
            stateEntry.SetModified();
        }

        //public static void AddRuleViolations(this ModelStateDictionary modelState, IEnumerable<RuleViolation> errors)
        //{
        //    foreach (RuleViolation issue in errors)
        //    {
        //        modelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
        //    }
        //}
    }
    #endregion
}
